package com.xyy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyy.common.PageResult;
import com.xyy.dto.*;
import com.xyy.entity.User;
import com.xyy.mapper.UserMapper;
import com.xyy.service.UserService;
import com.xyy.util.JwtUtil;
import com.xyy.util.PasswordUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import com.xyy.service.EmailService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;


/**
 * 用户服务实现类
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private EmailService emailService;

    @Autowired
    private HttpServletRequest request;

    @Override
    public Map<String, Object> register(UserRegisterDTO registerDTO) {
        // 验证密码
        if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
            throw new RuntimeException("两次输入的密码不一致");
        }

        // 检查用户名是否已存在
        User existUser = getUserByUsername(registerDTO.getUsername());
        if (existUser != null) {
            throw new RuntimeException("用户名已存在");
        }

        // 检查手机号是否已存在
        if (StringUtils.hasText(registerDTO.getPhone())) {
            existUser = getUserByPhone(registerDTO.getPhone());
            if (existUser != null) {
                throw new RuntimeException("手机号已被注册");
            }
        }

        // 检查邮箱是否已存在
        if (StringUtils.hasText(registerDTO.getEmail())) {
            existUser = getUserByEmail(registerDTO.getEmail());
            if (existUser != null) {
                throw new RuntimeException("邮箱已被注册");
            }
            
            // 验证邮箱验证码
            if (StringUtils.hasText(registerDTO.getEmailCode())) {
                boolean isValidCode = verifyRegisterEmailCode(registerDTO.getEmail(), registerDTO.getEmailCode());
                if (!isValidCode) {
                    throw new RuntimeException("邮箱验证码错误或已过期");
                }
            } else {
                throw new RuntimeException("请输入邮箱验证码");
            }
        }

        // 创建用户
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(PasswordUtil.encode(registerDTO.getPassword()));
        user.setNickname(registerDTO.getNickname());
        user.setPhone(registerDTO.getPhone());
        user.setEmail(registerDTO.getEmail());
        user.setGender(registerDTO.getGender());
        user.setFavoriteFood(registerDTO.getFavoriteFood());
        user.setFavoritePlace(registerDTO.getFavoritePlace());
        user.setFavoriteSchool(registerDTO.getFavoriteSchool());
        user.setStatus(1);

        // 保存用户
        save(user);

        // 生成token
        String token = jwtUtil.generateToken(user.getUsername(), user.getId());

        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("user", user);
        return result;
    }

    @Override
    public Map<String, Object> login(UserLoginDTO loginDTO) {
        // 根据用户名查询用户
        User user = getUserByUsername(loginDTO.getUsername());
        if (user == null) {
            throw new RuntimeException("用户名或密码错误");
        }

        // 验证密码
        if (!PasswordUtil.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new RuntimeException("用户名或密码错误");
        }

        // 检查用户状态
        if (user.getStatus() == 0) {
            throw new RuntimeException("账户已被禁用");
        }

        // 更新最后登录信息
        String ip = getClientIp();
        updateLastLoginInfo(user.getId(), ip);

        // 生成token
        String token = jwtUtil.generateToken(user.getUsername(), user.getId());

        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("user", user);
        return result;
    }

    @Override
    public void sendEmailCode(String email) {
        // 检查邮箱是否存在
        User user = getUserByEmail(email);
        if (user == null) {
            throw new RuntimeException("该邮箱未注册");
        }

        // 生成验证码
        String code = generateRandomCode();
        
        // 发送邮件
        boolean sendSuccess = emailService.sendPasswordResetCode(email, code);
        
        if (sendSuccess) {
            // 将验证码存储到Redis，有效期5分钟
            String key = "email_code:" + email;
            redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
            
            log.info("验证码已发送到邮箱：{}", email);
        } else {
            throw new RuntimeException("发送验证码失败，请稍后重试");
        }
    }

    @Override
    public void resetPassword(PasswordResetDTO resetDTO) {
        // 验证新密码
        if (!resetDTO.getNewPassword().equals(resetDTO.getConfirmPassword())) {
            throw new RuntimeException("两次输入的密码不一致");
        }

        // 根据用户名查询用户
        User user = getUserByUsername(resetDTO.getUsername());
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        if ("security".equals(resetDTO.getResetType())) {
            // 密保找回
            if (!resetDTO.getFavoriteFood().equals(user.getFavoriteFood()) ||
                !resetDTO.getFavoritePlace().equals(user.getFavoritePlace()) ||
                !resetDTO.getFavoriteSchool().equals(user.getFavoriteSchool())) {
                throw new RuntimeException("密保问题答案错误");
            }
        } else if ("email".equals(resetDTO.getResetType())) {
            // 邮箱找回
            String key = "email_code:" + user.getEmail();
            String storedCode = redisTemplate.opsForValue().get(key);
            if (storedCode == null || !storedCode.equals(resetDTO.getEmailCode())) {
                throw new RuntimeException("验证码错误或已过期");
            }
            // 删除验证码
            redisTemplate.delete(key);
        } else {
            throw new RuntimeException("重置方式不正确");
        }

        // 更新密码
        user.setPassword(PasswordUtil.encode(resetDTO.getNewPassword()));
        updateById(user);
    }

    @Override
    public User getUserByUsername(String username) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        return getOne(wrapper);
    }

    @Override
    public User getUserByEmail(String email) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getEmail, email);
        return getOne(wrapper);
    }

    @Override
    public User getUserByPhone(String phone) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getPhone, phone);
        return getOne(wrapper);
    }

    @Override
    public void updateLastLoginInfo(Long userId, String ip) {
        User user = new User();
        user.setId(userId);
        user.setLastLoginTime(LocalDateTime.now());
        updateById(user);
    }

    /**
     * 生成随机验证码
     */
    private String generateRandomCode() {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(10));
        }
        return code.toString();
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp() {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    @Override
    public void validateUserEmail(String username, String email) {
        // 根据用户名查询用户
        User user = getUserByUsername(username);
        if (user == null) {
            throw new RuntimeException("用户名不存在");
        }
        
        // 验证邮箱是否匹配
        if (!email.equals(user.getEmail())) {
            throw new RuntimeException("用户名与邮箱不匹配");
        }
    }
    
    @Override
    public void sendRegisterEmailCode(String email) {
        // 检查邮箱是否已被注册
        User existingUser = getUserByEmail(email);
        if (existingUser != null) {
            throw new RuntimeException("该邮箱已被注册");
        }
        
        // 生成6位随机验证码
        String code = generateRandomCode();
        
        // 发送邮件
        boolean sendSuccess = emailService.sendVerificationCode(email, code);
        
        if (sendSuccess) {
            // 将验证码存储到Redis，有效期5分钟
            String key = "email_verify:" + email;
            redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
            
            log.info("注册验证码已发送到邮箱：{}", email);
        } else {
            throw new RuntimeException("发送验证码失败，请稍后重试");
        }
    }
    
    @Override
    public boolean verifyRegisterEmailCode(String email, String code) {
        String key = "email_verify:" + email;
        String storedCode = redisTemplate.opsForValue().get(key);
        
        if (storedCode != null && storedCode.equals(code)) {
            // 验证成功后删除验证码
            redisTemplate.delete(key);
            return true;
        }
        return false;
    }
    
    @Override
    public boolean verifySecurityQuestions(String username, String favoriteFood, String favoritePlace, String favoriteSchool) {
        // 根据用户名查询用户
        User user = getUserByUsername(username);
        if (user == null) {
            return false;
        }
        
        // 验证密保问题答案
        return favoriteFood.equals(user.getFavoriteFood()) &&
               favoritePlace.equals(user.getFavoritePlace()) &&
               favoriteSchool.equals(user.getFavoriteSchool());
    }
    
    @Override
    public boolean verifyEmailCode(String username, String email, String emailCode) {
        // 根据用户名查询用户
        User user = getUserByUsername(username);
        if (user == null) {
            return false;
        }
        
        // 验证邮箱是否匹配
        if (!email.equals(user.getEmail())) {
            return false;
        }
        
        // 验证验证码
        String key = "email_code:" + email;
        String storedCode = redisTemplate.opsForValue().get(key);
        
        if (storedCode != null && storedCode.equals(emailCode)) {
            // 验证成功后删除验证码
            redisTemplate.delete(key);
            return true;
        }
        return false;
    }
    
    @Override
    public void updateUserAvatar(Long userId, String avatarUrl) {
        User user = getById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        
        user.setAvatar(avatarUrl);
        updateById(user);
        
        log.info("用户头像更新成功，用户ID：{}，头像URL：{}", userId, avatarUrl);
    }


    public void updateUser(UserUpdateDTO updateDTO) {
        User user = getById(updateDTO.getId());
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 检查手机号是否被其他用户使用
        if (StringUtils.hasText(updateDTO.getPhone()) && !updateDTO.getPhone().equals(user.getPhone())) {
            User existUser = getUserByPhone(updateDTO.getPhone());
            if (existUser != null) {
                throw new RuntimeException("手机号已被其他用户使用");
            }
        }

        // 检查邮箱是否被其他用户使用
        if (StringUtils.hasText(updateDTO.getEmail()) && !updateDTO.getEmail().equals(user.getEmail())) {
            User existUser = getUserByEmail(updateDTO.getEmail());
            if (existUser != null) {
                throw new RuntimeException("邮箱已被其他用户使用");
            }
        }

        // 更新用户信息
        user.setNickname(updateDTO.getNickname());
        user.setPhone(updateDTO.getPhone());
        user.setEmail(updateDTO.getEmail());
        user.setGender(updateDTO.getGender());
        user.setBirthDate(updateDTO.getBirthDate());
        user.setIdCard(updateDTO.getIdCard());
        user.setAddress(updateDTO.getAddress());
        user.setFavoriteFood(updateDTO.getFavoriteFood());
        user.setFavoritePlace(updateDTO.getFavoritePlace());
        user.setFavoriteSchool(updateDTO.getFavoriteSchool());
        
        if (updateDTO.getStatus() != null) {
            user.setStatus(updateDTO.getStatus());
        }

        updateById(user);
        
        log.info("用户信息更新成功，用户ID：{}", user.getId());
    }

    @Override
    public void deleteUser(Long userId) {
        User user = getById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 软删除用户
        removeById(userId);
        
        log.info("用户软删除成功，用户ID：{}", userId);
    }

    @Override
    public void batchDeleteUser(List<Long> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            throw new RuntimeException("用户ID列表不能为空");
        }

        // 批量软删除用户
        removeByIds(userIds);
        
        log.info("批量软删除用户成功，用户ID列表：{}", userIds);
    }

    @Override
    public PageResult<User> pageQueryUsers(UserQueryDTO queryDTO, PageQueryDTO pageDTO) {
        // 构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        
        // 用户名模糊查询
        if (StringUtils.hasText(queryDTO.getUsername())) {
            queryWrapper.like(User::getUsername, queryDTO.getUsername());
        }
        
        // 昵称模糊查询
        if (StringUtils.hasText(queryDTO.getNickname())) {
            queryWrapper.like(User::getNickname, queryDTO.getNickname());
        }
        
        // 手机号模糊查询
        if (StringUtils.hasText(queryDTO.getPhone())) {
            queryWrapper.like(User::getPhone, queryDTO.getPhone());
        }
        
        // 邮箱模糊查询
        if (StringUtils.hasText(queryDTO.getEmail())) {
            queryWrapper.like(User::getEmail, queryDTO.getEmail());
        }
        
        // 性别查询
        if (queryDTO.getGender() != null) {
            queryWrapper.eq(User::getGender, queryDTO.getGender());
        }
        
        // 状态查询
        if (queryDTO.getStatus() != null) {
            queryWrapper.eq(User::getStatus, queryDTO.getStatus());
        }
        
        // 时间范围查询
        if (StringUtils.hasText(queryDTO.getStartTime())) {
            queryWrapper.ge(User::getCreateTime, queryDTO.getStartTime());
        }
        if (StringUtils.hasText(queryDTO.getEndTime())) {
            queryWrapper.le(User::getCreateTime, queryDTO.getEndTime());
        }
        
        // 按创建时间倒序排列
        queryWrapper.orderByDesc(User::getCreateTime);
        
        // 执行分页查询
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<User> page = 
            new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageDTO.getCurrent(), pageDTO.getSize());
        
        page = page(page, queryWrapper);
        
        // 构建分页结果
        return PageResult.of(page.getRecords(), page.getTotal(), page.getCurrent(), page.getSize());
    }

    @Override
    public User getUserById(Long userId) {
        User user = getById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        return user;
    }

    @Override
    public void toggleUserStatus(Long userId, Integer status) {
        User user = getById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        if (status != 0 && status != 1) {
            throw new RuntimeException("状态值无效，只能是0（禁用）或1（启用）");
        }

        user.setStatus(status);
        updateById(user);
        
        log.info("用户状态更新成功，用户ID：{}，新状态：{}", userId, status);
    }

    /**
     * 分页查询已删除的用户
     */
    @Override
    public PageResult<User> getDeletedUsersPage(Integer current, Integer size) {
        // 参数验证
        if (current == null || current < 1) current = 1;
        if (size == null || size < 1) size = 10;
        
        // 查询所有已删除用户
        List<User> allDeletedUsers = baseMapper.selectDeletedUsers();
        Long total = baseMapper.countDeletedUsers();
        
        // 手动分页
        int startIndex = (current - 1) * size;
        int endIndex = Math.min(startIndex + size, allDeletedUsers.size());
        
        List<User> pageUsers = allDeletedUsers.subList(startIndex, endIndex);
        
        return PageResult.of(pageUsers, total, (long) current, (long) size);
    }

    @Override
    public void restoreUser(Long userId) {
        // 使用自定义方法查询已删除的用户，避免@TableLogic的影响
        User user = baseMapper.selectDeletedUserById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在或未被删除");
        }
        
        // 使用自定义UPDATE语句恢复用户（设置deleted=0）
        int result = baseMapper.restoreUserById(userId);
        if (result == 0) {
            throw new RuntimeException("恢复用户失败，可能用户已被其他操作修改");
        }
        
        log.info("用户恢复成功，用户ID：{}", userId);
    }

    @Override
    public void batchRestoreUsers(List<Long> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            throw new RuntimeException("用户ID列表不能为空");
        }
        
        // 批量恢复用户
        List<User> users = listByIds(userIds);
        if (users.size() != userIds.size()) {
            throw new RuntimeException("部分用户不存在");
        }
        
        for (User user : users) {
            if (user.getDeleted() == 0) {
                log.warn("用户{}未被删除，跳过恢复", user.getId());
                continue;
            }
            user.setDeleted(0);
        }
        
        updateBatchById(users);
        log.info("批量恢复用户成功，用户ID列表：{}", userIds);
    }

    @Override
    public void permanentlyDeleteUser(Long userId) {
        // 使用自定义方法查询已删除的用户，避免@TableLogic的影响
        User user = baseMapper.selectDeletedUserById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在或未被删除");
        }
        
        // 永久删除用户
        removeById(userId);
        
        log.info("用户永久删除成功，用户ID：{}", userId);
    }

    @Override
    public void batchPermanentlyDeleteUsers(List<Long> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            throw new RuntimeException("用户ID列表不能为空");
        }
        
        // 检查所有用户是否都已被软删除
        List<User> users = listByIds(userIds);
        if (users.size() != userIds.size()) {
            throw new RuntimeException("部分用户不存在");
        }
        
        for (User user : users) {
            if (user.getDeleted() == 0) {
                throw new RuntimeException("用户" + user.getId() + "未被软删除，无法永久删除");
            }
        }
        
        // 批量永久删除用户
        removeByIds(userIds);
        
        log.info("批量永久删除用户成功，用户ID列表：{}", userIds);
    }
    
    /**
     * 将Map转换为User对象
     */
    private User mapToUser(Map<String, Object> map) {
        User user = new User();
        if (map.containsKey("id")) user.setId(Long.valueOf(map.get("id").toString()));
        if (map.containsKey("username")) user.setUsername((String) map.get("username"));
        if (map.containsKey("nickname")) user.setNickname((String) map.get("nickname"));
        if (map.containsKey("avatar")) user.setAvatar((String) map.get("avatar"));
        if (map.containsKey("phone")) user.setPhone((String) map.get("phone"));
        if (map.containsKey("email")) user.setEmail((String) map.get("email"));
        if (map.containsKey("gender")) user.setGender((Integer) map.get("gender"));
        if (map.containsKey("birth_date")) user.setBirthDate((java.time.LocalDate) map.get("birth_date"));
        if (map.containsKey("id_card")) user.setIdCard((String) map.get("id_card"));
        if (map.containsKey("address")) user.setAddress((String) map.get("address"));
        if (map.containsKey("favorite_food")) user.setFavoriteFood((String) map.get("favorite_food"));
        if (map.containsKey("favorite_place")) user.setFavoritePlace((String) map.get("favorite_place"));
        if (map.containsKey("favorite_school")) user.setFavoriteSchool((String) map.get("favorite_school"));
        if (map.containsKey("status")) user.setStatus((Integer) map.get("status"));
        if (map.containsKey("last_login_time")) user.setLastLoginTime((java.time.LocalDateTime) map.get("last_login_time"));
        if (map.containsKey("deleted")) user.setDeleted((Integer) map.get("deleted"));
        if (map.containsKey("create_time")) user.setCreateTime((java.time.LocalDateTime) map.get("create_time"));
        if (map.containsKey("update_time")) user.setUpdateTime((java.time.LocalDateTime) map.get("update_time"));
        return user;
    }
} 